package com.sxkawzp.handler;

import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import com.sxkawzp.anno.DataScope;
import com.sxkawzp.anno.SubDataScope;
import com.sxkawzp.consts.DataScopeConst;
import com.sxkawzp.enums.Relation;
import com.sxkawzp.util.CurrentLoginUser;
import com.sxkawzp.util.DataScopeException;
import com.sxkawzp.util.DataScopeHolder;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author suxingkang
 * @version 1.0
 * @since 2025/1/17 15:09
 */
public class MultiDataPermissionHandlerImpl implements MultiDataPermissionHandler {

    private final CurrentLoginUser currentLoginUser;

    public MultiDataPermissionHandlerImpl(CurrentLoginUser currentLoginUser) {
        this.currentLoginUser = currentLoginUser;
    }

    @Override
    public Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {
        DataScope queryScope = getAndClearDataScope();
        if (Objects.isNull(queryScope)) {
            return null;
        }
        return buildQueryDataScopeSql(queryScope);
    }

    private DataScope getAndClearDataScope() {
        DataScope queryScope = DataScopeHolder.get();
        DataScopeHolder.clear();
        return queryScope;
    }

    public Expression buildQueryDataScopeSql(DataScope dataScope) {
        int scope = currentLoginUser.getScope();
        if (DataScopeConst.DATA_SCOPE_ALL == scope) {
            return null;
        }
        SubDataScope[] rules = dataScope.rules();
        if (rules.length == 0) {
            throw new DataScopeException("没有设置对应权限，请联系管理员！");
        }

        if (dataScope.paramPretreatment()) {
            doParamPretreatment(scope, dataScope);
        }

        Expression expression = null;
        for (SubDataScope rule : rules) {
            if (scope != rule.scope()) {
                continue;
            }
            Relation relation = rule.conditionRelation();
            String tableAlias = rule.tableAlias();
            String columnName = rule.columnName();
            String paramName = rule.paramName();

            checkDataScopeParamIntegrality(tableAlias, columnName, paramName);

            Object param = DataScopeHolder.getParam(paramName);
            // 根据查询权限范围，对 sql 进行不同的处理
            switch (rule.valueCompare().getCode()) {
                case DataScopeConst.EQUALS_VAL:
                    EqualsTo equalsTo = new EqualsTo();
                    equalsTo.withLeftExpression(new Column(tableAlias + "." + columnName));
                    if (param instanceof String) {
                        equalsTo.withRightExpression(new StringValue((String) param));
                    } else {
                        equalsTo.withRightExpression(new LongValue((Long) param));
                    }
                    expression = dealToRelationWay(relation, expression, equalsTo);
                    break;
                case DataScopeConst.NO_EQUALS_VAL:
                    NotEqualsTo notEqualsTo = new NotEqualsTo();
                    notEqualsTo.withLeftExpression(new Column(tableAlias + "." + columnName));
                    if (param instanceof String) {
                        notEqualsTo.withRightExpression(new StringValue((String) param));
                    } else {
                        notEqualsTo.withRightExpression(new LongValue((Long) param));
                    }
                    expression = dealToRelationWay(relation, expression, notEqualsTo);
                    break;
                case DataScopeConst.LIKE_VAL:
                    LikeExpression likeExpression = new LikeExpression();
                    likeExpression.withLeftExpression(new Column(tableAlias + "." + columnName));
                    likeExpression.withRightExpression(new StringValue(param + "%"));
                    expression = dealToRelationWay(relation, expression, likeExpression);
                    break;
                case DataScopeConst.IN_VAL:
                    if (param instanceof List) {
                        InExpression inExpression = new InExpression();
                        inExpression.withLeftExpression(new Column(tableAlias + "." + columnName));
                        List<?> paramList = (List<?>) param;
                        // 如果没有对应管辖的范围，则直接报错
                        if (CollectionUtils.isEmpty(paramList)) {
                            throw new DataScopeException("权限参数范围设置错误，请联系管理员授权！");
                        }
                        List<Expression> longValueList = new ArrayList<>(paramList.size());
                        ((List<?>) param).forEach(e -> longValueList.add(new LongValue((Long) e)));
                        inExpression.withRightItemsList(new MultiExpressionList().withExpressionLists(Collections.singletonList(new ExpressionList(longValueList))));
                        expression = dealToRelationWay(relation, expression, inExpression);
                    } else {
                        throw new DataScopeException("权限参数类型设置错误，参数名：" + paramName);
                    }
                    break;
                default:
                    throw new DataScopeException("权限值比较方式【valueCompare】设置错误");
            }
        }
        return expression;
    }

    /**
     * 自动根据登陆人所拥有的数据权限填充一部分参数
     *
     * @param scope     登陆人数据权限
     * @param dataScope 权限注解配置
     */
    private void doParamPretreatment(int scope, DataScope dataScope) {
        if (scope == DataScopeConst.DATA_SCOPE_DEPT) {
            DataScopeHolder.addParam(DataScopeConst.CUR_DEPT_PARAM, currentLoginUser.getDeptId());
        } else if (scope == DataScopeConst.DATA_SCOPE_CUSTOM) {
            DataScopeHolder.addParam(DataScopeConst.CUR_USER_PARAM, currentLoginUser.getUserSelfDeptIds());
        } else if (scope == DataScopeConst.DATA_SCOPE_SELF) {
            DataScopeHolder.addParam(DataScopeConst.CUR_USER_PARAM, currentLoginUser.getUserId());
        } else if (scope == DataScopeConst.DATA_SCOPE_DEPT_AND_CHILD) {
            List<Long> childDeptIds = currentLoginUser.getChildDeptIds();
            if (childDeptIds != null && !childDeptIds.isEmpty()) {
                childDeptIds.add(currentLoginUser.getDeptId());
            } else {
                childDeptIds = Collections.singletonList(currentLoginUser.getDeptId());
            }
            DataScopeHolder.addParam(DataScopeConst.CUR_USER_PARAM, childDeptIds);
        }
    }


    private Expression dealToRelationWay(Relation relation, Expression e1, Expression e2) {
        if (Objects.isNull(e1)) {
            return e2;
        }
        if (Objects.isNull(e2)) {
            return e1;
        }
        if (Relation.AND.equals(relation)) {
            return new AndExpression(e1, e2);
        } else if (Relation.OR.equals(relation)) {
            return new OrExpression(e1, e2);
        } else {
            throw new DataScopeException("权限连接方式设置错误");
        }
    }


    private void checkDataScopeParamIntegrality(String tableAlias, String columnName, String paramName) {
        if (!StringUtils.hasText(tableAlias)) {
            throw new DataScopeException("权限表别名【tableAlias】不能为空");
        }

        if (!StringUtils.hasText(columnName)) {
            throw new DataScopeException("权限控制列名【columnName】不能为空");
        }

        if (!StringUtils.hasText(paramName)) {
            throw new DataScopeException("权限参数名称【paramName】不能为空");
        }
    }
}
